package cn.bonoon.kernel.web.handlers.loader;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import cn.bonoon.handler.impl.StandardAutoManager;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.support.entities.Persistable;
import cn.bonoon.kernel.support.models.CommonItem;
import cn.bonoon.kernel.support.searcher.ItemSelectedFilter;
import cn.bonoon.kernel.web.annotations.AutoDataLoader;
import cn.bonoon.kernel.web.annotations.components.ComboMultipleChecker;

/**
 * <pre>
 * 这里需要区分两种情况：
 * <p>
 * 1.单选情况，单选有下拉、树及列表，其中列表又可分为没分页和带分页的；没有分页的与之前的一样，
 * 如果是带分页的话，则当前的被选中的项可能不在第一个分页里，所以在修改的时候，该选项上可能值出现
 * 为所选中的ID并不能显示被选中者的名称。【考虑的解决方案是，对从数据库加载完成后的数据进行处理，
 * 如果在第一页中没有该记录，则从数据库再把这条记录读取出来，并取得列表中的第一条记录；因为，如果
 * 修改的时候能能显示所选中的值，用户在进行下面页翻转的时候，该选择框所显示的选中的记录是不会变的，
 * 除非已经重新选中其它选项。】
 * </p>
 * <p>
 * 2.多选情况，也有两种可能：
 *   2.1 非分页情况；可以用js处理，但这样就得修改实体转值的算法，把一对多的关联数据读取出来；
 *   也可以后台处理，这样就得在ComboAutoLoaderHandler处理为里加上相应的处理函数。
 *   2.2 分页情况；如果选中多个值，并且在不同的分页里，而且选中的值也大于每页显示的数量【应该把所
 *   有选中的都放在第一页的前面（不管选中的数量是多少）】
 * </p>
 * 
 * 由参数{@link cn.bonoon.kernel.web.models.IdParameter IdParameter}传过来的ID值是当前combo所在宿主的ID
 * 如果是单选的话是不需要处理这个ID的，因为在界面生成的时候已经对<code>&lt;input/&gt;</code>或者<code>&lt;select&gt;&lt;/select&gt;</code>
 * 进行的赋值
 * </pre>
 * @author jackson
 * @see AbstractAutoLoaderHandler
 */
public abstract class ComboAutoLoaderHandler extends AbstractLoaderHandler{
	protected final String propertyName;
	protected final ComboMultipleChecker multiple;
	protected final StandardAutoManager manager;

	protected ComboAutoLoaderHandler(StandardAutoManager manager, Class<?> queryClass, AutoDataLoader loader, Field field) throws Exception {
		super(manager.getSesrcher(loader.value()), manager, queryClass);
		this.propertyName = field.getName();
		this.multiple = field.getAnnotation(ComboMultipleChecker.class);
		this.manager = manager;
	}

	protected ComboAutoLoaderHandler(StandardAutoManager manager, AutoDataLoader loader, Field field) throws Exception {
		super(manager.getSesrcher(loader.value()), manager);
		this.propertyName = field.getName();
		this.multiple = field.getAnnotation(ComboMultipleChecker.class);
		this.manager = manager;
	}
	
	public boolean isMultiple(){
		return null != multiple;
	}

	protected class SelectedFilter implements ItemSelectedFilter{
		private final List<String> selectedIds = new ArrayList<String>();
		
		public SelectedFilter(ReadEvent event){
			Long sourceId = event.getLong(propertyName);
			if(null != sourceId && sourceId > 0){
				String name = multiple.multipleProperty();
				if(name.isEmpty()){
					name = propertyName;
				}
				StringBuilder ql = new StringBuilder("select x.id from ");
				Class<? extends Persistable> linkClass = multiple.entityClass();
				if(Persistable.class.equals(linkClass)){
					//由被关联的实体来维护关系
					ql.append(entityDescriptor.getName()).append(" x join x.").append(name).append(" y ");
				}else{
					ql.append(linkClass.getName()).append(" y join y.").append(name).append(" x ");
				}
				ql.append("where y.id=?");
				for(Object id : manager.query(ql.toString(), sourceId)){
					selectedIds.add(String.valueOf(id));
				}
			}
		}
		
		@Override
		public boolean doFilter(CommonItem item) {
			return selectedIds.contains(item.getId());
		}
	}
}
